package com.jrx.anytxn.param.service.aviator.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jrx.anytxn.i18n.response.TxnPage;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnRuntimeException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.dto.aviator.ConditionGroupReq;
import com.jrx.anytxn.param.dto.aviator.RequestRulePageReq;
import com.jrx.anytxn.param.dto.aviator.RuleReq;
import com.jrx.anytxn.param.dto.aviator.RuleRes;
import com.jrx.anytxn.param.entity.RmAviatorRuleInfoWithBLOBs;
import com.jrx.anytxn.param.mapper.ext.ExtRmAviatorRuleInfoMapper;
import com.jrx.anytxn.param.service.aviator.IRuleService;
import com.jrx.anytxn.param.utils.ConditionGroupUtils;
import io.netty.util.internal.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
 * @author
 */
@Service
@CacheConfig(cacheNames = "RULE")
public class RuleServiceImpl implements IRuleService {
    private static final Logger logger = LoggerFactory.getLogger(RuleServiceImpl.class);
    @Resource
    private ExtRmAviatorRuleInfoMapper extRmAviatorRuleInfoMapper;

    @Autowired
    private ISegmentService segmentService;


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Caching(evict={@CacheEvict(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req.ruleType"),
            @CacheEvict(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req.productNumber+'_'+#req" +
                    ".ruleType",condition ="#req.productNumber !=null && !''.equals(#req.productNumber)")
    })
    public void registerRule(RuleReq req) {
        try {
            buildExpression(req);
            RmAviatorRuleInfoWithBLOBs aviatorRuleInfo = this.transformationAviatorRuleInfo(req);
            aviatorRuleInfo.setId(segmentService.getId("RmAviatorRuleInfo"));
            aviatorRuleInfo.setRecordVersionNumber(Constant.VERSION_NUMBER);
            extRmAviatorRuleInfoMapper.extInsertSelective(aviatorRuleInfo);
        } catch (Exception e) {
            logger.info("创建规则失败抛出异常=="+e);
            throw new TxnRuntimeException(TxnRespCode.ERROR.getCode(), TxnRespCode.BIZ_ERROR.getMsg());
        }
    }

    @Caching(evict={@CacheEvict(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req.ruleType"),
            @CacheEvict(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req.productNumber+'_'+#req" +
                    ".ruleType",condition ="#req.productNumber !=null && !''.equals(#req.productNumber)")
    })
    @Override
    public void modifyRule(RuleReq req) {
        try {
            buildExpression(req);
            RmAviatorRuleInfoWithBLOBs aviatorRuleInfo = this.transformationAviatorRuleInfo(req);
            extRmAviatorRuleInfoMapper.updateByOIdAndTenId(aviatorRuleInfo);
        } catch (Exception e) {
            logger.error("更新规则表异常:",e);
            throw new TxnRuntimeException(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getMsg());
        }
    }

    @Caching(evict={@CacheEvict(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req.ruleType"),
            @CacheEvict(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req.productNumber+'_'+#req" +
                    ".ruleType",condition ="#req.productNumber !=null && !''.equals(#req.productNumber)")
    })
    @Override
    public void cancelByIdOrRuleType(RuleReq req) {
        try {
            RmAviatorRuleInfoWithBLOBs aviatorRuleInfo = this.transformationAviatorRuleInfo(req);
            extRmAviatorRuleInfoMapper.deleteByIdOrRuleType(aviatorRuleInfo);
        } catch (Exception e) {
            logger.error("删除规则表异常:",e);
            throw new TxnRuntimeException(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getMsg());
        }
    }

    @Override
    public void cancelByIds(List<Long> ids,String tenantId) {
        try {
            if (CollectionUtils.isEmpty(ids)) {
                return;
            }
            for (Long id : ids) {
                extRmAviatorRuleInfoMapper.deleteByIdAndTenId(id,tenantId);
            }
        } catch (Exception e) {
            logger.error("删除规则表异常:",e);
            throw new TxnRuntimeException(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getMsg());
        }
    }

    @Caching(cacheable={@Cacheable(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req" +
            ".ruleType",condition ="#req.productNumber ==null || ''.equals(#req.productNumber)"),
            @Cacheable(key = "'rule_'+#req.tenantId+'_'+#req.organizationNumber+'_'+#req.productNumber+'_'+#req" +
            ".ruleType",condition ="#req.productNumber !=null && !''.equals(#req.productNumber)")
    })
    @Override
    public List<RuleRes> getByIdOrRuleTypeRule(RuleReq req) {
        List<RuleRes> resultList;
        try {
            RmAviatorRuleInfoWithBLOBs aviatorRuleInfo = this.transformationAviatorRuleInfo(req);
            List<RmAviatorRuleInfoWithBLOBs> list = extRmAviatorRuleInfoMapper.selectByIdOrRuleTypeRule(aviatorRuleInfo);
            if (CollectionUtils.isEmpty(list)) {
                return Collections.emptyList();
            }
            resultList = new ArrayList<>();
            for (RmAviatorRuleInfoWithBLOBs obj : list) {
                resultList.add(transformationRuleDTO(obj));
            }
        } catch (Exception e) {
            logger.error("获取规则表异常:",e);
            throw new TxnRuntimeException(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getMsg());
        }
        return resultList;
    }

    @Override
    public List<RuleRes> getByIdAndTenIdAndType(RuleReq req) {
        List<RuleRes> resultList;
        RmAviatorRuleInfoWithBLOBs aviatorRuleInfo = this.transformationAviatorRuleInfo(req);
        List<RmAviatorRuleInfoWithBLOBs> list=extRmAviatorRuleInfoMapper.selectByIdAndTenIdAndType(aviatorRuleInfo);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        resultList = new ArrayList<>();
        for (RmAviatorRuleInfoWithBLOBs obj : list) {
            resultList.add(transformationRuleDTO(obj));
        }
        return resultList;
    }

    @Override
    public TxnPage<RuleRes> getPageByRuleType(RequestRulePageReq requestRulePageDTO) {
        TxnPage<RuleRes> page = new TxnPage<>();
        try {
            Page<RmAviatorRuleInfoWithBLOBs> pageList = PageHelper.startPage(requestRulePageDTO.getPage(), requestRulePageDTO.getRows(),Constant.ORDER_BY_SORT);
            RmAviatorRuleInfoWithBLOBs record = new RmAviatorRuleInfoWithBLOBs();
            record.setProductNumber(requestRulePageDTO.getProductNumber());
            record.setRuleType(requestRulePageDTO.getRuleType());
            record.setOrganizationNumber(requestRulePageDTO.getOrganizationNumber());
            record.setTenantId(requestRulePageDTO.getTenantId());
            if(org.apache.commons.lang.StringUtils.isNotBlank(requestRulePageDTO.getRuleId())){
                record.setId(Long.parseLong(requestRulePageDTO.getRuleId()));
            }
            List<RmAviatorRuleInfoWithBLOBs> list = extRmAviatorRuleInfoMapper.selectPageByRuleType(record);
            if (CollectionUtils.isEmpty(list)) {
                return null;
            }
            List<RuleRes> resultList = new ArrayList<>();
            for (RmAviatorRuleInfoWithBLOBs obj : list) {

                resultList.add(transformationRuleDTO(obj));
            }
            PageInfo<RmAviatorRuleInfoWithBLOBs> pageInfo1 = pageList.toPageInfo();

            page = new TxnPage<>(requestRulePageDTO.getPage(), requestRulePageDTO.getRows(), pageInfo1.getTotal(), resultList);


        } catch (Exception e) {
            logger.error("获取规则表异常:",e);
            throw new TxnRuntimeException(TxnRespCode.ERROR.getCode(), TxnRespCode.ERROR.getMsg());
        }
        return page;
    }

    /**
     * 转换为AviatorRuleInfo
     */
    private RmAviatorRuleInfoWithBLOBs transformationAviatorRuleInfo(RuleReq req) {
        //将条件DTO转换为条件json字符串
        if (null != req.getConditionGroup()) {
            ObjectMapper mapper = new ObjectMapper();

            String str;
            String ruleResult;
            try {
                str = mapper.writeValueAsString(req.getConditionGroup());
                ruleResult = mapper.writeValueAsString(req.getRuleResultMap());
            } catch (JsonProcessingException e) {
                logger.error("JSON转换字符串:" + e.getMessage(), e);
                throw new TxnRuntimeException("对象转换JSON字符串异常");
            }
            req.setRuleConditions(str);
            req.setRuleResult(ruleResult);
        }
        RmAviatorRuleInfoWithBLOBs aviatorRuleInfo = new RmAviatorRuleInfoWithBLOBs();
//        //类转换
        aviatorRuleInfo.setId(req.getId());
        aviatorRuleInfo.setTenantId(req.getTenantId());
        aviatorRuleInfo.setRuleConditions(req.getRuleConditions());
        aviatorRuleInfo.setRuleResult(req.getRuleResult());
        aviatorRuleInfo.setRuleName(req.getRuleName());
        aviatorRuleInfo.setRuleDescription(req.getRuleDescription());
        aviatorRuleInfo.setCreateBy(req.getCreateBy());
        aviatorRuleInfo.setCreateTime(req.getCreateTime());
        aviatorRuleInfo.setUpdateBy(req.getUpdateBy());
        aviatorRuleInfo.setUpdateTime(req.getUpdateTime());
        aviatorRuleInfo.setRulePriority(req.getRulePriority());
        aviatorRuleInfo.setProductNumber(req.getProductNumber());
        aviatorRuleInfo.setOrganizationNumber(req.getOrganizationNumber());
        aviatorRuleInfo.setRuleType(req.getRuleType());
        aviatorRuleInfo.setRuleStatus(req.getRuleStatus());
        aviatorRuleInfo.setCreateBy(req.getCreateBy());
        aviatorRuleInfo.setUpdateBy(req.getUpdateBy());
        return aviatorRuleInfo;
    }

    private RuleRes transformationRuleDTO(RmAviatorRuleInfoWithBLOBs aviatorRuleInfo) {
        RuleRes dto = new RuleRes();
        dto.setId(aviatorRuleInfo.getId());
        dto.setTenantId(aviatorRuleInfo.getTenantId());
        dto.setRuleConditions(aviatorRuleInfo.getRuleConditions());
        dto.setRuleResult(aviatorRuleInfo.getRuleResult());
        dto.setRuleName(aviatorRuleInfo.getRuleName());
        dto.setRuleDescription(aviatorRuleInfo.getRuleDescription());
        dto.setRuleType(aviatorRuleInfo.getRuleType());
        dto.setCreateBy(aviatorRuleInfo.getCreateBy());
        dto.setCreateTime(aviatorRuleInfo.getCreateTime());
        dto.setUpdateBy(aviatorRuleInfo.getUpdateBy());
        dto.setUpdateTime(aviatorRuleInfo.getUpdateTime());
        dto.setRulePriority(aviatorRuleInfo.getRulePriority());
        dto.setProductNumber(aviatorRuleInfo.getProductNumber());
        dto.setOrganizationNumber(aviatorRuleInfo.getOrganizationNumber());
        dto.setRuleStatus(aviatorRuleInfo.getRuleStatus());
        if (!StringUtils.isEmpty(aviatorRuleInfo.getRuleConditions())) {
            ObjectMapper mapper = new ObjectMapper();
            ConditionGroupReq group;
            try {
                group = mapper.readValue(aviatorRuleInfo.getRuleConditions(), ConditionGroupReq.class);
            } catch (IOException e) {
                logger.error("JSON转换对象" + e.getMessage(), e);
                throw new TxnRuntimeException("JSON字符串转换对象异常");
            }
            dto.setConditionGroup(group);
        }
        if (!StringUtils.isEmpty(aviatorRuleInfo.getRuleConditions())) {
            ObjectMapper mapper = new ObjectMapper();
            Map ruleResultMap;
            try {
                ruleResultMap = mapper.readValue(aviatorRuleInfo.getRuleResult(), Map.class);
            } catch (IOException e) {
                logger.error("JSON转换集合" + e.getMessage(), e);
                throw new TxnRuntimeException("JSON字符串转换集合异常");
            }
            dto.setRuleResultMap(ruleResultMap);
        }

        buildExpression(dto);
        return dto;
    }

    private RuleReq buildExpression(RuleReq req) {
        ConditionGroupReq groupReq = req.getConditionGroup();
        if (groupReq != null) {
            req.setExpression(ConditionGroupUtils.nodeExpression(groupReq));
            List<String> fields = new ArrayList<>();
            List<String> valueTypes = new ArrayList<>();
            List<String> defaultTypes = new ArrayList<>();
            ConditionGroupUtils.expressionField(groupReq, fields, valueTypes, defaultTypes);

            req.setExpField(fields.toArray(new String[fields.size()]));
            req.setExpValueType(valueTypes.toArray(new String[valueTypes.size()]));
            req.setExpDefaultValue(defaultTypes.toArray(new String[defaultTypes.size()]));
        }
        return req;
    }

}
